/*
 * SPDX-FileCopyrightText: 2024 Andrew Gunnerson
 * SPDX-License-Identifier: GPL-3.0-only
 */

@file:OptIn(ExperimentalUnsignedTypes::class)

package com.sanji.audio_test.format

import android.content.Context
import android.media.MediaCodecList
import android.media.MediaFormat
import android.util.Log
import com.sanji.audio_test.R

/**
 * 采样率信息抽象类
 *
 * @param default 默认采样率
 * @param presets 在UI中显示为预设的固定采样率选项
 */
sealed class SampleRateInfo(
    val default: UInt,
    /** 在UI中显示为预设的固定采样率选项 */
    val presets: UIntArray,
) {
    /**
     * 验证采样率是否有效
     *
     * @param rate 要验证的采样率
     * @throws IllegalArgumentException 如果采样率无效
     */
    abstract fun validate(rate: UInt)

    /**
     * 将可能无效的采样率值转换为最近的有效值
     */
    abstract fun toNearest(rate: UInt): UInt

    /**
     * 格式化采样率，用于用户界面显示
     */
    fun format(context: Context, rate: UInt): String =
        context.getString(R.string.format_sample_rate, rate.toString())

    companion object {
        private val TAG = SampleRateInfo::class.java.simpleName

        /**
         * 根据编解码器能力创建采样率信息对象
         *
         * @param format 媒体格式
         * @param tryDefault 尝试使用的默认采样率
         * @return 采样率信息对象
         */
        fun fromCodec(format: MediaFormat, tryDefault: UInt): SampleRateInfo {
            val codecList = MediaCodecList(MediaCodecList.REGULAR_CODECS)

            for (info in codecList.codecInfos) {
                // 跳过非编码器
                if (!info.isEncoder) {
                    continue
                }

                // 获取编解码器能力
                val capabilities = try {
                    info.getCapabilitiesForType(format.getString(MediaFormat.KEY_MIME))
                } catch (e: IllegalArgumentException) {
                    continue
                }

                // 检查能力是否存在且格式是否支持
                if (capabilities == null || !capabilities.isFormatSupported(format)) {
                    continue
                }

                val audioCapabilities = capabilities.audioCapabilities
                    ?: throw IllegalArgumentException("${info.name} 编码器没有音频能力")

                // 尝试获取支持的采样率列表
                val rates = try {
                    audioCapabilities.supportedSampleRates
                } catch (e: NullPointerException) {
                    Log.w(TAG, "系统缺少 2e961480fe0f4e87f2b7f621b276035864124f69 修复", e)
                    null
                }
                
                // 如果有明确的采样率列表，创建离散采样率信息
                if (rates != null && rates.isNotEmpty()) {
                    val ratesUnsigned = rates.toUIntArray()
                    val default = DiscreteSampleRateInfo.toNearest(ratesUnsigned, tryDefault)!!

                    return DiscreteSampleRateInfo(ratesUnsigned, default)
                }

                // 如果有采样率范围，创建范围采样率信息
                val rateRanges = audioCapabilities.supportedSampleRateRanges
                if (rateRanges.isNotEmpty()) {
                    val rateRangesUnsigned = rateRanges
                        .map { it.lower.toUInt()..it.upper.toUInt() }
                        .toTypedArray()
                    val default = RangedSampleRateInfo.toNearest(rateRangesUnsigned, tryDefault)!!

                    return RangedSampleRateInfo(rateRangesUnsigned, default)
                }
            }

            throw IllegalArgumentException("找不到适合 $format 的编码器")
        }
    }
}

/**
 * 计算两个无符号整数的绝对差值
 */
private fun absDiff(a: UInt, b: UInt): UInt = if (a > b) {
    a - b
} else {
    b - a
}

/**
 * 范围采样率信息类
 *
 * @param ranges 支持的采样率范围数组
 * @param default 默认采样率
 */
class RangedSampleRateInfo(
    val ranges: Array<UIntRange>,
    default: UInt,
) : SampleRateInfo(default, uintArrayOf(default)) {
    /**
     * 验证采样率是否在支持的范围内
     */
    override fun validate(rate: UInt) {
        if (!ranges.any { rate in it }) {
            throw IllegalArgumentException(
                "采样率 $rate 不在范围内: ${ranges.contentToString()}")
        }
    }

    /** 将采样率限制在 [ranges] 中最近的范围内 */
    override fun toNearest(rate: UInt): UInt = toNearest(ranges, rate)!!

    companion object {
        /**
         * 找到范围内最接近指定采样率的值
         */
        fun toNearest(ranges: Array<UIntRange>, rate: UInt): UInt? = ranges
            .asSequence()
            .map { rate.coerceIn(it) }  // 将采样率限制在范围内
            .minByOrNull { absDiff(rate, it) }  // 找到差值最小的
    }
}

/**
 * 离散采样率信息类
 *
 * @param choices 支持的采样率选项列表
 * @param default 默认采样率
 */
class DiscreteSampleRateInfo(
    /** 为了简单起见，所有选项都用作预设 */
    private val choices: UIntArray,
    default: UInt,
) : SampleRateInfo(default, choices) {
    init {
        require(choices.isNotEmpty()) { "选项列表不能为空" }
    }

    /**
     * 验证采样率是否在支持的选项中
     */
    override fun validate(rate: UInt) {
        if (rate !in choices) {
            throw IllegalArgumentException("不支持的采样率 $rate: " +
                    choices.contentToString())
        }
    }

    /** 在 [choices] 中找到最接近 [rate] 的采样率 */
    override fun toNearest(rate: UInt): UInt = toNearest(choices, rate)!!

    companion object {
        /**
         * 在选项中找到最接近指定采样率的值
         */
        fun toNearest(choices: UIntArray, rate: UInt): UInt? =
            choices.minByOrNull { absDiff(rate, it) }
    }
}